<template>
  <pre :class="$style.pre" v-html="prettyString"></pre>
</template>

<script>
export default {
  name: 'JsonPrettyPrint',
  props: {
    jsonString: {
      type: [String, Array, Object],
      default: '',
      required: true
    }
  },
  computed: {
    prettyString() {
      try {
        const string =
          String(this.jsonString) === this.jsonString
            ? this.jsonString
            : JSON.stringify(this.jsonString, null, 2)
        const handleString = string
          .replace(/&/g, '&')
          .replace(/</g, '<')
          .replace(/>/g, '>')
        const regex =
          /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g

        return handleString.replace(regex, (match) => {
          let className = 'number'

          if (/^"/.test(match)) {
            if (/:$/.test(match)) {
              className = 'key'
            } else {
              className = 'string'
            }
          } else if (/true|false/.test(match)) {
            className = 'boolean'
          } else if (/null/.test(match)) {
            className = 'null'
          }

          return `<span class="${className}">${match}</span>`
        })
      } catch (e) {
        return '<span style="padding: 20px 0;">解析失败</span>'
      }
    }
  }
}
</script>

<style module>
.pre {
  outline: 1px solid #ccc;
  background-color: #ffffff;
  padding: 5px;
  margin: 5px;
  text-align: left;
  overflow: hidden;
  :global {
    .string {
      color: #e91e63;
    }

    .number {
      color: #00bcd4;
    }

    .boolean {
      color: #ff00ff;
    }

    .null {
      color: #9e9e9e;
    }

    .key {
      color: #3753a9;
    }
  }
}
</style>
